package com.ruoyi.business.service.impl;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.ruoyi.business.domain.HistoricActivity;
import com.ruoyi.business.domain.ServiceItem;
import com.ruoyi.business.service.IDefinitionNodeService;
import com.ruoyi.business.service.IProcessService;
import com.ruoyi.business.service.IServiceItemService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.system.service.ISysUserService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.business.mapper.CarPackageAuditMapper;
import com.ruoyi.business.domain.CarPackageAudit;
import com.ruoyi.business.service.ICarPackageAuditService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

/**
 * 审核列Service业务层处理
 * 
 * @author wolfcode
 * @date 2021-08-27
 */
@Service
public class CarPackageAuditServiceImpl implements ICarPackageAuditService 
{
    @Autowired
    private CarPackageAuditMapper carPackageAuditMapper;
    @Autowired
    private IProcessService processService;

    @Autowired
    private IServiceItemService serviceItemService;

    @Autowired
    private IDefinitionNodeService definitionNodeService;

    @Autowired
    private ISysUserService sysUserService;

    /**
     * 查询审核列
     * 
     * @param id 审核列ID
     * @return 审核列
     */
    @Override
    public CarPackageAudit selectCarPackageAuditById(Long id)
    {
        return carPackageAuditMapper.selectCarPackageAuditById(id);
    }

    /**
     * 查询审核列列表
     * 
     * @param carPackageAudit 审核列
     * @return 审核列
     */
    @Override
    public List<CarPackageAudit> selectCarPackageAuditList(CarPackageAudit carPackageAudit)
    {
        List<CarPackageAudit> carPackageAudits = carPackageAuditMapper.selectCarPackageAuditList(carPackageAudit);


        for (CarPackageAudit packageAudit : carPackageAudits) {
            //套餐信息
            String json = packageAudit.getServiceItemInfo();
            ServiceItem serviceItem = JSON.parseObject(json, ServiceItem.class);
            packageAudit.setServiceItem(serviceItem);

            //task相关信息
            Task task = processService.getTaskByInstanceId(carPackageAudit.getInstanceId());

            if(task != null){
                packageAudit.setTaskId(task.getId());
                packageAudit.setTaskName(task.getName());
            }else{
                packageAudit.setTaskName("已结束");
            }
            //用户信息
        }




        return carPackageAudits;
    }

    /**
     * 新增审核列
     * 
     * @param carPackageAudit 审核列
     * @return 结果
     */
    @Override
    public int insertCarPackageAudit(CarPackageAudit carPackageAudit)
    {
        carPackageAudit.setCreateTime(DateUtils.getNowDate());
        return carPackageAuditMapper.insertCarPackageAudit(carPackageAudit);
    }

    /**
     * 修改审核列
     * 
     * @param carPackageAudit 审核列
     * @return 结果
     */
    @Override
    public int updateCarPackageAudit(CarPackageAudit carPackageAudit)
    {
        return carPackageAuditMapper.updateCarPackageAudit(carPackageAudit);
    }

    /**
     * 删除审核列对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteCarPackageAuditByIds(String ids)
    {
        return carPackageAuditMapper.deleteCarPackageAuditByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除审核列信息
     * 
     * @param id 审核列ID
     * @return 结果
     */
    @Override
    public int deleteCarPackageAuditById(Long id)
    {
        return carPackageAuditMapper.deleteCarPackageAuditById(id);
    }

    @Override
    public void cancelApply(Long carPackageAuditId) {
        //满足撤销操作条件
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(carPackageAuditId);
        if(audit == null || audit.getStatus() == CarPackageAudit.STATUS_CANCEL){
            throw  new BusinessException("参数不合法， 只有非撤销状态才可以进行撤销");
        }
        //审核记录对象变动
        audit.setStatus(CarPackageAudit.STATUS_CANCEL);
        audit.setAuditors("");
        carPackageAuditMapper.updateCarPackageAudit(audit);
        //套餐服务对象变动
        //修改状态为：初始化
        String json = audit.getServiceItemInfo();
        ServiceItem serviceItem = JSON.parseObject(json, ServiceItem.class);
        serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_INIT);
        //@TODO 乐观锁  -- 悲观锁
        //serviceItemService.updateServiceItem(serviceItem);
        serviceItemService.updateStatus(serviceItem.getId(), serviceItem.getAuditStatus());

        //审核流程变动-删除
        processService.deleteProcessInstance(audit.getInstanceId(),"用户撤销");

    }

    @Override
    public List<CarPackageAudit> findTodoList(CarPackageAudit carPackageAudit) {
        List<CarPackageAudit> list = new ArrayList<>();
        //查询当前登录用户的待办task信息
        //按照下面方式操作， 查询出来是指定用户所有待办任务，而页面要求需要进行分页，此时怎办？
       /* List<Task> tasks = processService.selectTodoTaskList(
                CarPackageAudit.DEFINITION_KEY,
                ShiroUtils.getUserId().toString());*/
        //如果需要分页， 查询数据就不能是全部， 需要进行分页查询
        //分页查询语句： select * from xxx where xxx  limit ？，？
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();  //当前页
        //第二问号 ？：每页显示条数
        Integer pageSize = pageDomain.getPageSize();
        //第一问号 ？ ： 每页第一条数据的偏移量
        Integer startNum = (pageNum - 1) * pageSize;
        List<Task> tasks = processService.selectTodoTaskList(CarPackageAudit.DEFINITION_KEY,
                ShiroUtils.getUserId().toString(), startNum, pageSize);
        //遍历task集合，将task任务关联的审核记录信息绑定
        for (Task task : tasks) {
            //之前审核开始之后， 已经讲审核记录对象id作为businesskey绑定在流程实例中了
            //那么只需要获取实例就可以获取id值
            ProcessInstance instance = processService.getProcessInstanceById(task.getProcessInstanceId());
            String businessKey = instance.getBusinessKey();  //carPackageAuditId
            CarPackageAudit audit = carPackageAuditMapper.
                    selectCarPackageAuditById(Long.parseLong(businessKey));
            audit.setTaskId(task.getId());
            audit.setTaskName(task.getName());

            audit.setServiceItem(JSON.parseObject(audit.getServiceItemInfo(), ServiceItem.class));

            //设置其他关联审核记录属性
            //audit.setxxx
            list.add(audit);
        }

        //分页时还差一个总记录数：
        Long total = processService.selectTodoTaskCount(CarPackageAudit.DEFINITION_KEY,
                ShiroUtils.getUserId().toString());
        //怎么丢出去
        //封装成Page对象返回： 因为ruoyi框架做分页时需要使用total跟list跟分页相关数据，所以要返回
        Page<CarPackageAudit> page = new Page<>();
        page.setTotal(total);
        page.setPageNum(pageNum);
        page.setPageSize(pageSize);
        page.addAll(list);
        return page;
    }

    @Override
    @Transactional
    public void complete(String taskId, Boolean auditStatus, String comment) {
        String commentStr = auditStatus?"【同意】":"【拒绝】";
        if(StringUtils.hasText(comment)){
            comment += commentStr;
        }
        //对流程： task 领取， 执行task(添加备注)  对下一个点进行数据准备(变量/候选人)
        // 套餐明细状态（审核中有可能不变， 也有可能审核通过）
        // 审核记录状态 (审核中有可能不变， 也有可能审核通过）
        //------------------------------------------------------------------------
        //1:通过taskId查询task对象
        Task task = processService.getTaskById(taskId);
        //位置1：后续需要进行修改审核记录对象状态，而流程开始时，审核记录对象id是作为businesskey绑定在流程中的
        //所以可以通过流程实例获取审核记录对象
        ProcessInstance instance = processService.getProcessInstanceById(task.getProcessInstanceId());
        //2:领取task任务， 执行 task任务， 添加备注， 设置下一个节点变量
        processService.claimAndComplete(task, ShiroUtils.getUserId().toString() ,auditStatus, comment);
        //3:获取下一个任务节点
        Task nextTask = processService.getTaskByInstanceId(task.getProcessInstanceId());




        //位置2： 获取实例前要考虑流程是否已经执行完成
        //ProcessInstance instance = processService.getProcessInstanceById(task.getProcessInstanceId());
        String businessKey = instance.getBusinessKey();// carPackageAuditId
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(Long.parseLong(businessKey));
       // ServiceItem item2 = JSON.parseObject(audit.getServiceItemInfo(), ServiceItem.class);
        //4:判断任务节点是否null
        if(nextTask != null){
            //processService.setVariable(nextTask, "money", item2.getDiscountPrice().longValue());
            //5：如果不为空， 执行下面逻辑
            //5.1:判断审核auditStatus是否是同意(通过)
            List<String> names = new ArrayList<>();
            if(auditStatus){
                //5.2：如果通过
                //5.2.1 下一个节点审核候选人设置
                List<SysUser> auditors = definitionNodeService
                        .queryAuditorsByTaskDefinitionKey(nextTask.getTaskDefinitionKey());
                for (SysUser auditor : auditors) {
                    processService.addCandidateUser(nextTask.getId(), auditor.getUserId().toString());
                    names.add(auditor.getUserName());
                }
            }else{
                //5.3: 如果不通过
                //5.3.1:修改审核记录的状态-审核拒绝
                audit.setStatus(CarPackageAudit.STATUS_REJECT);
                //5.3.2:修改下一个节点审核候选人-审核流程创建者
                names.add(audit.getCreateByName());
                processService.addCandidateUser(nextTask.getId(), audit.getCreateBy());
            }
            audit.setAuditors(JSON.toJSONString(names));
            carPackageAuditMapper.updateCarPackageAudit(audit);
        }else{
            //6：如果为null， 说明流程结束
            //6.1:套餐明细状态-审核通过
            String json = audit.getServiceItemInfo();
            ServiceItem item = JSON.parseObject(json, ServiceItem.class);
            item.setAuditStatus(ServiceItem.AUDITSTATUS_APPROVED);
            serviceItemService.updateStatus(item.getId(), item.getAuditStatus());

            //6.2:修改审核记录的状态-审核通过
            audit.setStatus(CarPackageAudit.STATUS_PASS);
            //audit.setServiceItemInfo(JSON.toJSONString(item));
            audit.setAuditors("");  //审核人
            carPackageAuditMapper.updateCarPackageAudit(audit);
        }
    }

    @Override
    @Transactional
    public void updateServiceItem(Long carPackageAuditId, ServiceItem serviceItem) {
        //修改套餐信息
        serviceItemService.updateServiceItemNoCondition(serviceItem);
        //同步修改审核记录中套餐信息
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(carPackageAuditId);
        audit.setServiceItemInfo(JSON.toJSONString(serviceItem));
        carPackageAuditMapper.updateCarPackageAudit(audit);
    }

    @Override
    @Transactional
    public void reApply(String taskId, Long carPackageAuditId) {

        //领取任务，执行任务 设置备注
        Task task = processService.getTaskById(taskId);
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(carPackageAuditId);
        ServiceItem item = JSON.parseObject(audit.getServiceItemInfo(), ServiceItem.class);
        //设置参数money
        //processService.setVariable(task, "money", item.getDiscountPrice().longValue());
        processService.claimAndComplete
                (task, ShiroUtils.getUserId().toString(), true, "重写审核");

        //下一个节点设置
        Task nextTask = processService.getTaskByInstanceId(task.getProcessInstanceId());
        processService.setVariable(nextTask, "money", item.getDiscountPrice().longValue());
        //候选人设置
        List<SysUser> auditors = definitionNodeService.
                queryAuditorsByTaskDefinitionKey(nextTask.getTaskDefinitionKey());
        List<String> names = new ArrayList<>();
        for (SysUser auditor : auditors) {
            processService.addCandidateUser(nextTask.getId(), auditor.getUserId().toString());
            names.add(auditor.getUserName());
        }
        //套餐信息的状态-审核中
        //审核记录状态-审核中
        audit.setAuditors(JSON.toJSONString(names));
        audit.setStatus(CarPackageAudit.STATUS_IN_ROGRESS);
        carPackageAuditMapper.updateCarPackageAudit(audit);

    }

    @Override
    public List<CarPackageAudit> findDoneList(CarPackageAudit carPackageAudit) {
        List<CarPackageAudit> list = new ArrayList<>();
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();  //当前页
        Integer pageSize = pageDomain.getPageSize();
        Integer startNum = (pageNum - 1) * pageSize;
        List<HistoricTaskInstance> tasks = processService.selectDoneTaskList(CarPackageAudit.DEFINITION_KEY,
                ShiroUtils.getUserId().toString(), startNum, pageSize);
        for (HistoricTaskInstance task : tasks) {
            //ProcessInstance instance = processService.getProcessInstanceById(task.getProcessInstanceId());
            HistoricProcessInstance instance = processService.getHistoricProcessInstanceById(task.getProcessInstanceId());
            String businessKey = instance.getBusinessKey();  //carPackageAuditId
            CarPackageAudit audit = carPackageAuditMapper.
                    selectCarPackageAuditById(Long.parseLong(businessKey));
            audit.setTaskId(task.getId());
            audit.setTaskName(task.getName());
            audit.setServiceItem(JSON.parseObject(audit.getServiceItemInfo(), ServiceItem.class));
            audit.setDoneTime(task.getEndTime());
            list.add(audit);
        }
        Long total = processService.selectDoneTaskCount(CarPackageAudit.DEFINITION_KEY,
                ShiroUtils.getUserId().toString());

        Page<CarPackageAudit> page = new Page<>();
        page.setTotal(total);
        page.setPageNum(pageNum);
        page.setPageSize(pageSize);
        page.addAll(list);
        return page;
    }

    @Override
    public List<HistoricActivity> selectHistoryList(String instanceId) {

        List<HistoricActivityInstance> instanceList = processService.selectHistoryList(instanceId);


        List<HistoricActivity> list  = new ArrayList<>();


        //进行属性填充
        for (HistoricActivityInstance instance : instanceList) {
            HistoricActivity historicActivity = new HistoricActivity();

            //BeanUtils.copyProperties(historicActivity, instance);  //apache 目标在前， 源后
            //BeanUtils.copyProperties(instance, historicActivity);  //spring 源在前， 目标后
            //BeanUtils   --- srping   相对简单--不支持map拷贝-底层使用内省机制
            //BeanUtils   --- apache  功能最强 -- 支持map拷贝-底层使用内省机制 + map /get/put
            //规则： 同名属性复制
            BeanUtils.copyProperties(instance, historicActivity);

            //处理人
            SysUser user = sysUserService.selectUserById(Long.parseLong(instance.getAssignee()));
            historicActivity.setAssigneeName(user.getUserName());

            //审批意见
            String comment = processService.getTaskComment(instance.getTaskId());
            historicActivity.setComment(comment);


            list.add(historicActivity);
        }

        return list;
    }
}
